package bma.common.netty.pool;

import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;

import bma.common.langutil.ai.stack.AIStack;
import bma.common.langutil.io.HostPort;
import bma.common.langutil.pipeline.CommonPipelineBuilder;
import bma.common.netty.NettyChannelPipeline;
import bma.common.netty.NettyUtil;
import bma.common.netty.client.NettyClientBootstrap;
import bma.common.netty.handler.ChannelHandlerPlaceholder;

public class SimpleNettyChannelPoolFactory implements NettyChannelPoolFactory {

	final org.slf4j.Logger log = org.slf4j.LoggerFactory
			.getLogger(SimpleNettyChannelPoolFactory.class);

	protected NettyClientBootstrap bootstrap;
	protected CommonPipelineBuilder<ChannelHandler> pipelineBuilder;

	public NettyClientBootstrap getBootstrap() {
		return bootstrap;
	}

	public void setBootstrap(NettyClientBootstrap bootstrap) {
		this.bootstrap = bootstrap;
	}

	public CommonPipelineBuilder<ChannelHandler> getPipelineBuilder() {
		return pipelineBuilder;
	}

	public void setPipelineBuilder(
			CommonPipelineBuilder<ChannelHandler> pipelineBuilder) {
		this.pipelineBuilder = pipelineBuilder;
	}

	@Override
	public boolean makeObject(final AIStack<Channel> stack, HostPort key) {
		ChannelPipelineFactory fac = new ChannelPipelineFactory() {

			@Override
			public ChannelPipeline getPipeline() throws Exception {
				ChannelPipeline p = Channels.pipeline();
				p.addLast(NettyUtil.HANDLER_PLACEHOLDER,
						new ChannelHandlerPlaceholder());
				if (pipelineBuilder != null) {
					pipelineBuilder.buildPipeline(new NettyChannelPipeline(p));
				}
				p.addLast("last", new SimpleChannelUpstreamHandler() {
					@Override
					public void messageReceived(ChannelHandlerContext ctx,
							MessageEvent e) throws Exception {
						if (log.isDebugEnabled()) {
							log.debug("{} message miss : {}", ctx.getChannel(),
									e.getMessage());
						}						
					}

					@Override
					public void exceptionCaught(ChannelHandlerContext ctx,
							ExceptionEvent e) throws Exception {
						if (log.isDebugEnabled()) {
							log.debug("{} exception miss : {}",
									ctx.getChannel(), e.getCause());
						}						
					}
				});
				return p;
			}
		};
		ChannelFuture cf = bootstrap.connect(key.createInetSocketAddress(),
				null, fac);
		cf.addListener(new ChannelFutureListener() {

			@Override
			public void operationComplete(ChannelFuture future)
					throws Exception {
				if (future.isSuccess()) {
					stack.success(future.getChannel());
				} else {
					stack.failure(future.getCause());
				}
			}
		});
		return false;
	}

	@Override
	public void activateObject(HostPort key, Channel obj) {

	}

	@Override
	public void passivateObject(HostPort key, Channel obj) {

	}

	@Override
	public boolean validateObject(HostPort key, Channel obj) {
		return obj.isConnected();
	}

	@Override
	public void destroyObject(HostPort key, Channel obj) {
		NettyUtil.closeOnFlush(obj);
	}

}
